home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / mac / Sample Code / Interapplication Comm / AECDEV⁄AEDAEMON / AECDEV.PPC.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  17.7 KB  |  375 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        AECDEV.PPC.c
  3.  
  4.     Contains:    This file contains the AppleEvent code that creates the
  5.                 AppleEvent,  and PPC toolbox code that finds and transfers the data to the 
  6.                 Backgrounder.
  7.                 It also contains the PBCatSearch code.
  8.  
  9.     Written by: C.K. Haun    
  10.  
  11.     Copyright:    Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved.
  12.  
  13.                 You may incorporate this Apple sample source code into your program(s) without
  14.                 restriction. This Apple sample source code has been provided "AS IS" and the
  15.                 responsibility for its operation is yours. You are not permitted to redistribute
  16.                 this Apple sample source code as "Apple sample source code" after having made
  17.                 changes. If you're going to re-distribute the source, we require that you make
  18.                 it clear in the source that the code was descended from Apple sample source
  19.                 code, but that you've made changes.
  20.  
  21.     Change History (most recent first):
  22.                 7/20/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  23.                 
  24.  
  25. */
  26. #include <TextUtils.h>
  27. #include "AECdev.h"
  28. /* FindATarget prompts the user for a target application (through the PPC browser) */
  29. /* and a document for that application to open (with Standard File) */
  30. /* Once it's gotten that information, it bundles up the information about the */
  31. /* document to be opened into an APpleEvent list, adds the address of the target */
  32. /* application to the event, and passes the data to the routine that starts the PPC */
  33. /* transfer */
  34. void FindATarget(CDEVHnd storage)
  35. {
  36.     OSErr theErr = noErr;
  37.     LocationNameRec theLoc;
  38.     PortInfoRec theRec;
  39.     AEDesc theAddress, docDesc;
  40.     AEDescList theList;
  41.     AliasHandle myAlias;
  42.     StandardFileReply myReply;
  43.     TargetID theID;
  44.     AppleEvent theEvent;
  45.     Str32 tWext;
  46.     Str32 txWext;
  47.     /* Get the strings that will appear in the PPC browser */
  48.     GetIndString(tWext, kStringsID, kBrowse1);
  49.     GetIndString(txWext, kStringsID, kBrowse2);
  50.     /* Choose the Application you want to send the event to */
  51.     if (noErr == PPCBrowser(tWext, txWext, false, &theLoc, &theRec, nil, nil)) {
  52.         /* Now I'll create the ODOC applevent */
  53.         /* Create the targetID for the selected application first */
  54.         theID.name = theRec.name;
  55.         theID.location = theLoc;
  56.         theErr = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), &theAddress);
  57.         if (theErr == noErr) {
  58.         /* Create the whole event */
  59.             theErr = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &theAddress, kAutoGenerateReturnID, kAnyTransactionID,
  60.                                         &theEvent);
  61.             if (theErr == noErr) {
  62.                 /* now get a document to pass */
  63.                 StandardGetFile(nil, -1, nil, &myReply);
  64.                 if (myReply.sfGood) {
  65.                     /* odoc passed a list of FSSpecs, so make a list */
  66.                     /* even though this will only contain one spec, you still need a list */
  67.                     theErr = AECreateList(nil, 0, false, &theList);
  68.                     if (theErr == noErr) {
  69.                         /* create an alias out of the file spec */
  70.                         /* I'm not real sure why I did this, since there is a system coercion handler for */
  71.                         /* alias to FSSpec, but I'm paranoid (and goofy) */
  72.                         theErr = NewAlias(nil, &myReply.sfFile, &myAlias);
  73.                         if (theErr == noErr) {
  74.                             HLock((Handle)myAlias);
  75.                             /* now create an alias descriptor */
  76.                             theErr = AECreateDesc(typeAlias, (Ptr)*myAlias, GetHandleSize((Handle)myAlias), &docDesc);
  77.                             if (theErr == noErr) {
  78.                                 DisposeHandle((Handle)myAlias);      /* no longer needed */
  79.                                 /* put it in the list */
  80.                                 theErr = AEPutDesc(&theList, 0, &docDesc);
  81.                                 if (theErr == noErr) {
  82.                                     /* and put the list in the event */
  83.                                     theErr = AEPutParamDesc(&theEvent, keyDirectObject, &theList);
  84.                                     if (theErr == noErr) {
  85.                                         /* now I'm passing the data portion of the AppleEvent to the handler */
  86.                                         /* that will open a PPC channel and pass the information along */
  87.                                         FireTheEvent(theEvent.dataHandle, storage);
  88.                                     }                       /* putparamdesc err */
  89.                                 }                           /* putDesc error */
  90.                                 /* dispose of all the appleevent strutures I've been using */
  91.                                 AEDisposeDesc(&docDesc);
  92.                             }                               /* docDesc creation error */
  93.                         }                                   /* alias creation error */
  94.                         AEDisposeDesc(&theList);
  95.                     }                                       /* list create error */
  96.                     
  97.                 }                                           /* standardfile cancel */
  98.                 AEDisposeDesc(&theEvent);
  99.             }                                               /* event create error */
  100.             AEDisposeDesc(&theAddress);
  101.         }                                                   /* desc 1 error */
  102.     }                                                       /* browser cancel or error */
  103. } /* end FindATarget */
  104.  
  105. /* FindAEBuddy searches for the port to use to send the event.  In this */
  106. /* case I'm using my AEDaemon application to send events for me.  */
  107. /* So, if first see if it's available by looking for it's port with */
  108. /* IPCListPorts.  If it isn't available, I search for it by */
  109. /* creator and file type with PBCatSearch, and launch it if I find it */
  110. /* Of course, if I launch it myself I need to give it some time */
  111. /* to register itself and come up in the PPC port list, so I'll set */
  112. /* a flag and go away for a while, checking back periodically until */
  113. /* the port comes up */
  114. /* You can use AEBuddy also for your app, though I'd change the name.... */
  115. void FindAEBuddy(CDEVHnd storage)
  116. {
  117.     Byte csState;
  118.     CDEVPtr tempPtr;
  119.     CursHandle watch;
  120.     /* Use NewPtrClear for these, so you don't have to worry about having */
  121.     /* garbage in the parameters to start */
  122.     IPCListPortsPBPtr listPtr = (IPCListPortsPBPtr)NewPtrClear(sizeof(IPCListPortsPBRec));
  123.     PPCPortPtr portWanted = (PPCPortPtr)NewPtrClear(sizeof(PPCPortRec));
  124.     LaunchParamBlockRec launchThis;
  125.     short realCount;
  126.     OSErr myError;
  127.     /* find AEBuddy, open our port, and pass the data */
  128.     /* remember NewPtrClear gave me a zeroed record, so all the parameters */
  129.     /* that I wanted nil'ed are. */
  130.     /* BY THE WAY: I could use the PPCBrowser again here, of course.  */
  131.     /* but remember, most of your users will have no idea that this CDEV is */
  132.     /* using another process, since faceless backgrounders don't show up */
  133.     /* in any list that most users can see */
  134.     watch = GetCursor(watchCursor);
  135.     SetCursor(*watch);                                      /* wait cursor */
  136.     csState = HGetState((Handle)storage);
  137.     HLock((Handle)storage);
  138.     tempPtr = *storage;                                     /* dereference this for clarity */
  139.     listPtr->requestCount = 1;                              /* only want one of them */
  140.     listPtr->portName = portWanted;
  141.     /* fill in the port a bit */
  142.     portWanted->name[0] = 1;                                /* making a "=" string here, telling IPCListPorts */
  143.     portWanted->name[1] = '=';                              /* that I don't care about the name of the port */
  144.     portWanted->portKindSelector = ppcByCreatorAndType;
  145.     portWanted->u.port.portCreator = 'MOOB';
  146.     portWanted->u.port.portType = 'APPL';
  147.     /* the location name will be nil, since I want to get the thing on the */
  148.     /* local machine, not across the vast net */
  149.     listPtr->locationName = nil;
  150.     listPtr->bufferPtr = (PortInfoArrayPtr)NewPtrClear(sizeof(PortInfoRec));
  151.     /* we're only asking for one, so we only need one array space allocated */
  152.     
  153.     myError = IPCListPorts(listPtr, false);                 /* getting it syncronously */
  154.     realCount = listPtr->actualCount;
  155.     /* so we don't forget */
  156.     if (myError == noErr) {
  157.         if (realCount == 0 && (*storage)->searchForTarget == false) {
  158.             /* The following segment is the PBCatSearch area */
  159.             
  160.             /* Couldn't find the port and we haven't launched it ourselves yet. */
  161.             /* So, let's see if we can find the app and launch it */
  162.             /* ourselves */
  163.             /* make a pointer to the block */
  164.             CSParamPtr csBlockPtr = (CSParamPtr)NewPtrClear(sizeof(CSParam));
  165.             long dirIDUnused;
  166.             Str32 nulString = "\p";
  167.             /* initialize the parameter block */
  168.             if (csBlockPtr) {
  169.                 csBlockPtr->ioSearchInfo1 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
  170.                 csBlockPtr->ioSearchInfo2 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
  171.                 if (csBlockPtr->ioSearchInfo1 && csBlockPtr->ioSearchInfo2) {
  172.                     csBlockPtr->ioMatchPtr = (FSSpecPtr)NewPtrClear(sizeof(FSSpec) * 1);        /* only looking for 1 */
  173.                     if (csBlockPtr->ioMatchPtr) {
  174.                         /* Now see if we can create an optimization buffer */
  175.                         csBlockPtr->ioOptBuffer = NewPtr(2048);
  176.                         if (csBlockPtr->ioOptBuffer)
  177.                             csBlockPtr->ioOptBufSize = 2048;
  178.                         else
  179.                             csBlockPtr->ioOptBufSize = 0;       /* no buffer, sorry */
  180.                         csBlockPtr->ioReqMatchCount = 1;
  181.                         csBlockPtr->ioSearchTime = 0;       /* no timeout */
  182.                     }
  183.                 }
  184.             }
  185.             /* check all my memory allocations here */
  186.             if (csBlockPtr->ioSearchInfo1 && csBlockPtr->ioSearchInfo2 && csBlockPtr->ioMatchPtr) {
  187.                 /* had memory, continue */
  188.                 HGetVol(nil, &csBlockPtr->ioVRefNum, &dirIDUnused);     /* get default volume for search */
  189.                 csBlockPtr->ioSearchInfo1->hFileInfo.ioNamePtr = nil;
  190.                 csBlockPtr->ioSearchInfo2->hFileInfo.ioNamePtr = nil;
  191.                 csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdCreator = 'MOOB';
  192.                 csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdType = 'APPL';
  193.                 csBlockPtr->ioSearchBits = fsSBFlFndrInfo;
  194.                 csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF;
  195.                 csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF;
  196.                 myError = PBCatSearch(csBlockPtr, false);       /* search sync */
  197.                 if (myError == noErr && csBlockPtr->ioActMatchCount != 0) {
  198.                 
  199.                     /* we found it, so launch it */
  200.                     launchThis.launchBlockID = extendedBlock;
  201.                     launchThis.launchEPBLength = extendedBlockLen;
  202.                     launchThis.launchFileFlags = nil;
  203.                     launchThis.launchControlFlags = launchContinue + launchNoFileFlags;
  204.                     launchThis.launchAppSpec = &csBlockPtr->ioMatchPtr[0];
  205.                     myError = LaunchApplication(&launchThis);
  206.                     if (myError == noErr) {
  207.                         /* it launched fine.  Set a flag so we can */
  208.                         /* check periodically until it's */
  209.                         /* PPC port comes up */
  210.                         (*storage)->searchForTarget = true;
  211.                     }
  212.                 } else {
  213.                     /* PBCat failed, we have no buddy on this volume.  Oh well */
  214.                     (*storage)->noBuddy = true;
  215.                 }
  216.             }                                               /* out of memory error */
  217.             if (csBlockPtr) {
  218.                 /* clean up what we allocated */
  219.                 if (csBlockPtr->ioSearchInfo1)
  220.                     DisposePtr((Ptr)csBlockPtr->ioSearchInfo1);
  221.                 if (csBlockPtr->ioSearchInfo2)
  222.                     DisposePtr((Ptr)csBlockPtr->ioSearchInfo2);
  223.                 if (csBlockPtr->ioMatchPtr)
  224.                     DisposePtr((Ptr)csBlockPtr->ioMatchPtr);
  225.                 if (csBlockPtr->ioOptBuffer)
  226.                     DisposePtr((Ptr)csBlockPtr->ioOptBuffer);
  227.                 DisposePtr((Ptr)csBlockPtr);
  228.             }
  229.             
  230.             /* catsearch section end */
  231.         } else {
  232.             PortInfoPtr portInfoTemp = (PortInfoPtr)listPtr->bufferPtr;
  233.             tempPtr->myPPCBlock->buddyPortPtr = (PPCPortPtr)NewPtrClear(sizeof(PPCPortRec));
  234.             /* we have a port to send to.  So, we'll first clear that flag... */
  235.             (*storage)->searchForTarget = false;
  236.             BlockMove((Ptr)&portInfoTemp->name, (Ptr)tempPtr->myPPCBlock->buddyPortPtr, sizeof(PPCPortRec));
  237.             
  238.         }
  239.     }                                                       /* listports err */
  240.     /* clean up the IPCListPorts memory */
  241.     if (listPtr->bufferPtr)
  242.         DisposePtr((Ptr)listPtr->bufferPtr);
  243.     if (listPtr)
  244.         DisposePtr((Ptr)listPtr);
  245.     if (portWanted)
  246.         DisposePtr((Ptr)portWanted);
  247.     
  248.     /* NOTE: I don't need to clean up listPtr->bufferPtr since I moved this into */
  249.     /* our other structure for later use */
  250.     InitCursor();
  251. } /* end FindAEBuddy */
  252.  
  253. /* FireTheEvent starts the PPC process.  It opens a port for us, and connects us to */
  254. /* AEBuddy.  The, through a series of asyncronous PPC calls, it transfers all the data */
  255. /* that makes up the APpleEvent we want to send. */
  256. void FireTheEvent(Handle packedEvent, CDEVHnd storage)
  257. {
  258.     /* all this will happen asyncronously, so no error back from this routine */
  259.     /* The first thing we do is open our own port, that completion routine will */
  260.     /* start a session with our target, that completion routine will write the data, */
  261.     /* that completion roiutine will end the session, then that completion routine */
  262.     /* will close the port.  */
  263.     /* Open our port */
  264.     /* first check to see if we've already opened a port.  If not, open one */
  265.     
  266.     Str32 myName;
  267.     PPCPortPtr myPort = (*storage)->myPPCBlock->myPort;
  268.     PPCOpenPBPtr openPtr = (PPCOpenPBPtr)(*storage)->myPPCBlock;
  269.     /* and once more, local 4 byte space is cheap */
  270.     MyPPCRecPtr ourPtr = (MyPPCRecPtr)openPtr;
  271.     GetIndString(myName, kStringsID, kMyName);
  272.     /* take the passed handle, make it our own ptr */
  273.     ourPtr->bufferSize = GetHandleSize(packedEvent);
  274.     ourPtr->buffer = NewPtr(GetHandleSize(packedEvent));
  275.     HLock(packedEvent);
  276.     BlockMove((Ptr)*packedEvent, ourPtr->buffer, GetHandleSize(packedEvent));
  277.     /*  Create our port */
  278.     myPort->nameScript = 0;
  279.     BlockMove((Ptr)&myName, (Ptr)&myPort->name, myName[0] + 1);
  280.     myPort->portKindSelector = ppcByCreatorAndType;
  281.     myPort->u.port.portCreator = 'ckh1';
  282.     myPort->u.port.portType = 'APPL';
  283.     openPtr->ioCompletion = NewPPCCompProc(OpenComplete);
  284.     
  285.     openPtr->serviceType = ppcServiceRealTime;              /* only valid one under 7.0 */
  286.     openPtr->resFlag = 0;
  287.     openPtr->portName = myPort;
  288.     openPtr->locationName = nil;
  289.     openPtr->networkVisible = false;
  290.     PPCOpen(openPtr, true);
  291.     (*storage)->eventPending = true;
  292. }
  293.  
  294. void OpenComplete(PPCStartPBPtr p)
  295. {
  296.     OSErr myErr;
  297.     /* cast this so it's easier to see */
  298.     MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
  299.     myErr = p->ioResult;
  300.     if (myErr == noErr) {
  301.         ourPtr->ourPort = p->portRefNum;
  302.        /* We opened our port successfully, so now connect to the buddy */
  303.     p->ioCompletion = NewPPCCompProc(StartComplete);
  304.     p->portName = ourPtr->buddyPortPtr;
  305.     p->locationName = nil;
  306.     PPCStart((PPCStartPBPtr)p, true);
  307.      } else {
  308.         DebugStr("\p error in opencomp");
  309.     }
  310. }
  311.  
  312. void StartComplete(PPCWritePBPtr p)
  313. {
  314.     OSErr fred;
  315.     MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
  316.     fred = p->ioResult;
  317.     if (fred == noErr) {
  318.     /* we started a session.  In this case, we were allowed to connect without authentication */
  319.     /* so we can start blasting data now */
  320.         p->bufferLength = ourPtr->bufferSize;
  321.         p->bufferPtr = ourPtr->buffer;
  322.         p->more = false;
  323.         /* pass ???? as the creator, the AEBuddy doesn't care who is sending it data */
  324.         p->blockCreator = kGenericCreator;
  325.         /* telling the buddy what type of data I'm sending */
  326.         /* since it _only_ accepts one type */
  327.         p->blockType = kMyTypeOfData;                       
  328.         p->ioCompletion = NewPPCCompProc(WriteComplete);
  329.         ourPtr->currentSessionRef = p->sessRefNum;
  330.         PPCWrite((PPCWritePBPtr)p, (Boolean)true);
  331.     } else {
  332.         DebugStr("\p error in startcomp");
  333.         p->ioCompletion = NewPPCCompProc(EndComplete);
  334.         PPCEnd((PPCEndPBPtr)p, true);
  335.         
  336.     }
  337. }
  338.  
  339. void WriteComplete(PPCEndPBPtr p)
  340. {
  341.     MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
  342.     OSErr fred;
  343.     fred = p->ioResult;
  344.     if (fred == noErr) {
  345.     /* We wrote everything we wanted to, time to end the session */
  346.         p->ioCompletion = NewPPCCompProc(EndComplete);
  347.         PPCEnd(p, true);
  348.     } else {
  349.         DebugStr("\p error in writecomp");
  350.         p->ioCompletion = NewPPCCompProc(EndComplete);
  351.         PPCEnd(p, true);
  352.         
  353.     }
  354. }
  355.  
  356. void EndComplete(PPCClosePBPtr p)
  357. {
  358.     MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
  359.     /* clear our session ref number please */
  360.     if (p->ioResult) {
  361.         DebugStr("\p error in endcomp");
  362.     }
  363.     /* I'm closing our port here, you could of course leave it open */
  364.     /* for repeated requests.  One reason why I'm not leaving it open is */
  365.     /* because I don't want anyone to try and talk to us */
  366.     ourPtr->currentSessionRef = nil;
  367.     /* and close the session out */
  368.     p->ioCompletion = nil;
  369.     PPCClose(p, false);
  370.     ourPtr->pB.openParam.portRefNum = nil;
  371. }
  372.  
  373.  
  374. #undef __BUILDINGCDEV__
  375.